package com.winning.gjhlht.ihe.cdaService.service;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.*;

import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

import org.apache.log4j.Logger;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.XMLWriter;
import org.springframework.stereotype.Service;
import org.xml.sax.SAXException;

import com.framework.FrameworkServlet;
import com.framework.helper.ServerSQLExecutorUtils;
import com.winning.common.Constans;
import com.winning.common.tools.CDASchemaValidateTool;
import com.winning.common.tools.XMLTool;
import com.winning.common.xmlSchema.SchemaSummary;
import com.winning.common.xmlSchema.schema.CDASchemaSAXValidator;
import com.winning.common.xmlSchema.schema.SchemaErrorHandler;
import com.winning.gjhlht.ihe.common.IHEConstans;
import com.winning.gjhlht.ihe.common.ValidateCDA;

/**
 * 类名称：BaseCDACreaterService
 * 类描述：创建CDA文档服务类
 * 创建人：liuwensheng
 * 创建时间：2017-1-11 下午2:43:52
 * 修改人：liuwensheng
 * 修改时间：2017-1-11 下午2:43:52
 * 修改备注：
 */
@Service(value = "com.winning.gjhlht.ihe.cdaService.service.BaseCDACreaterService")
public class BaseCDACreaterService implements IBaseCDACreaterServiceInter {
    //是否采用默认值来填充，从配置文件中读取
    private boolean useDefaultValue = true;

    public static final String ERROR_MESSAGE = "ERROR_MESSAGE";
    public static final String URL = "URL";

    private static Logger LOGGER = Logger.getLogger(Constans.LOG4J_PBS_LOGGER_ID);

    private static CDASchemaSAXValidator cdaSchemaSAXValidator = null;

    public static CDASchemaSAXValidator getCDASchemaSAXValidator() {
        if (cdaSchemaSAXValidator == null) {

            try {
                String xsdFilePath = "\\resource\\sdschemas\\PCHIS_CDA.xsd";
                String serverFilePath = FrameworkServlet.getServerFilePath();
                String filePath = serverFilePath + "\\WEB-INF\\classes\\";

                FileInputStream xsdFile = new FileInputStream(filePath + xsdFilePath);
                cdaSchemaSAXValidator = CDASchemaSAXValidator.newInstance(xsdFile);

            } catch (Exception e) {
                LOGGER.error(e, e.fillInStackTrace());
            }
        }
        return cdaSchemaSAXValidator;
    }

    /**
     * 生成CDA文档，如果有重复信息，生成多份CDA文档
     * 方法名称: createCDADocumentService
     *
     * @param
     * @return List<HashMap                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               <                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               String                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               ,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               Object>>  返回类型说明<br/>
     * @throws <br/>
     * @author zhaqiang@winning.com.cn<br/>
     * 创建时间：2017-3-10/上午8:47:04<br/>
     */
    @Override
    public List<HashMap<String, Object>> createCDADocumentService(String xm, String requestID, String cdaTempFileName,
                                                                  String basicSQL, Object[] param, String dbDataSourceID) {
        List<HashMap<String, Object>> createCDAInfo = new ArrayList<HashMap<String, Object>>();

        try {
            String errorMessage = null;

            String resultMessage = "";

            List<HashMap<String, Object>> rowListValue = new ArrayList<HashMap<String, Object>>();

            //文档名称 供CDA文档缓存到本地使用 一般不缓存到本地
            String cdaFileName = cdaTempFileName + "_" + xm + " _" + requestID;

            //获取XML文档DOM
            String cdaTempFilePath = "com/winning/ihe/cda/cdaTempFiles/" + cdaTempFileName + ".xml";

            Document configDocument = XMLTool.getXMLDocument(cdaTempFilePath);

            Element rootElementReader = configDocument.getRootElement();

            //执行数据库操作
            String sqlStr = basicSQL;

            LOGGER.info("-->查询CDA信息SQL：" + basicSQL);

            rowListValue = ServerSQLExecutorUtils.executeQueryOtherDB(basicSQL, param, dbDataSourceID);

            if (null == rowListValue || rowListValue.size() == 0) {
                LOGGER.info("生成CDA文档出现异常，异常信息：没有需要生成数据");
                return null;
            } else {

                List<HashMap<String, Object>> row = new ArrayList<HashMap<String, Object>>();

                int index = 1;

                //循环生成CDA文档
                for (HashMap<String, Object> map : rowListValue) {

                    LOGGER.info(" --> 开始生成第 " + index + "份CDA文档");

                    Document cdaDocument = DocumentHelper.createDocument();

                    //设置文档编码
                    cdaDocument.setXMLEncoding("utf-8");

                    HashMap<String, Object> result = new HashMap<String, Object>();

                    row.add(map);

                    //需要根据数据库查询结果，对CDA模板配置动态更新Entry节点
                    updateCDATempConfig(configDocument, row);

                    String rootElementName = XMLTool.getAttributeValue(rootElementReader,
                            IHEConstans.ROOT_ELEMENT_NAME_TEMP);

                    //Root根目录添加命名空间需要在创建根Element时，添加命名空间值，这样在给root element添加属性"xmlns"时才生效
                    Element cdaRootElement = cdaDocument.addElement(rootElementName,
                            IHEConstans.NAMP_SPACE_XMLNS_VALUE);

                    //1、命名空间属性
                    Element nameSpaceElement = rootElementReader.element(IHEConstans.NAME_SPACES_TEMP);
                    createNameSpaceElement(nameSpaceElement, cdaRootElement);

                    //2、请求头结构
                    Element headerElement = rootElementReader.element(IHEConstans.HEADER_ELEMENTS_TEMP);
                    createHeaderElement(headerElement, cdaRootElement, rowListValue);

                    //3、请求体结构
                    Element bodyElement = rootElementReader.element(IHEConstans.BODY_ELEMENTS_TEMP);
                    createBobyElement(bodyElement, cdaRootElement, rowListValue);

                    //还没有进行下一步的验证算法
                    errorMessage = searchErrorNodeToMessage(cdaDocument);

                    ValidateCDA validateCDA = new ValidateCDA();

                    //4.非空验证及更新：将存在异常error的节点删除，异常根据配置中参数的非空约束获得
                    cdaDocument = validateCDA.updateCDAXMLForDocument(cdaDocument, cdaFileName);

                    //删除 xsi:type 节点 替换为type
                    String cdaStr = cdaDocument.asXML();
                    cdaStr = cdaStr.replace("type=", "xsi:type=");
                    cdaDocument = DocumentHelper.parseText(cdaStr);

                    //开始校验CDA文档
                    LOGGER.info("-->需要校验的 CDA文档:" + cdaDocument.asXML());

                    //验证CDA文档
                    result = CDASchemaValidateTool.validateCDA(cdaDocument, "/common/resource/sdschemas/PCHIS_CDA.xsd");

                    LOGGER.info("-->验证CDA文档格式返回验证结果：" + result.toString());

                    result.put("cdaDocument", cdaDocument.asXML());

                    createCDAInfo.add(result);

                    index++;
                }
            }

        } catch (Exception e) {
            LOGGER.error(e, e.fillInStackTrace());
        }

        return createCDAInfo;
    }

    /**
     * 改造
     *
     * @param xm
     * @param requestID
     * @param cdaTempFileName
     * @param data
     * @return
     */
    @Override
    public Map<String, Object> createOneCDADocumentService(String xm, String requestID, String cdaTempFileName,
                                                           Map<String, Object> data) {
        Map<String, Object> result = new HashMap<String, Object>();


        String errorMessage = null;

        String resultMessage = "";
        HashMap<String, Object> rowMap = new HashMap<>();

        for (Map.Entry<String, Object> entry : data.entrySet()) {
            rowMap.put(entry.getKey(), entry.getValue());
        }
        List<HashMap<String, Object>> rowListValue = new ArrayList<HashMap<String, Object>>();
        rowListValue.add(rowMap);


        //"CDATemp.xml"
        //CDATempBeanConfig cdaConfig = CDATempBeanConfig.getInstance();
        Document cdaDocument = DocumentHelper.createDocument();
        //设置文档编码
        cdaDocument.setXMLEncoding("utf-8");

        String cdaFileName = cdaTempFileName + "_" + xm + " _" + requestID;


        try {
            //获取XML文档DOM
            String cdaTempFilePath = "com/winning/ihe/cda/cdaTempFiles/" + cdaTempFileName + ".xml";

            Document configDocument = XMLTool.getXMLDocument(cdaTempFilePath);

            Element rootElementReader = configDocument.getRootElement();

            //将数据结果集转换为map结构，key为模板配置中的columnFeild值
            //rowMap = sealDBTableValue(rs);

            if (null == rowMap || rowMap.size() == 0) {
                LOGGER.info("生成CDA文档出现异常，异常信息：没有需要生成数据1111111111");

                return null;
            }

            //需要根据数据库查询结果，对CDA模板配置动态更新Entry节点
            updateCDATempConfig(configDocument, rowListValue);

            String rootElementName = XMLTool.getAttributeValue(rootElementReader, IHEConstans.ROOT_ELEMENT_NAME_TEMP);

            //取得模板配置中的对CDA文档节点的验证
            //String findConditionStr = rootElementReader.attributeValue(IHEConstans.VALIDATE_NODES_TEMP) == null ? "" : rootElementReader.attributeValue(IHEConstans.VALIDATE_NODES_TEMP);

            //Root根目录添加命名空间需要在创建根Element时，添加命名空间值，这样在给root element添加属性"xmlns"时才生效
            Element cdaRootElement = cdaDocument.addElement(rootElementName, IHEConstans.NAMP_SPACE_XMLNS_VALUE);

            //1、命名空间属性
            Element nameSpaceElement = rootElementReader.element(IHEConstans.NAME_SPACES_TEMP);
            createNameSpaceElement(nameSpaceElement, cdaRootElement);

            //2、请求头结构
            Element headerElement = rootElementReader.element(IHEConstans.HEADER_ELEMENTS_TEMP);
            createHeaderElement(headerElement, cdaRootElement, rowListValue);

            //3、请求体结构
            Element bodyElement = rootElementReader.element(IHEConstans.BODY_ELEMENTS_TEMP);
            createBobyElement(bodyElement, cdaRootElement, rowListValue);

            //还没有进行下一步的验证算法
            errorMessage = searchErrorNodeToMessage(cdaDocument);
            ValidateCDA validateCDA = new ValidateCDA();

            /*******************************************************************
             在此处输出验证前的文档

             XMLWriter writer = new XMLWriter(new FileOutputStream("c://DemoX.xml"));
             writer.write(cdaDocument);
             *******************************************************************/

            //4.非空验证及更新：将存在异常error的节点删除，异常根据配置中参数的非空约束获得
            cdaDocument = validateCDA.updateCDAXMLForDocument(cdaDocument, cdaFileName);

            //			//5.对生成的CDA文档进行节点校验
            //			boolean boolResult = true; //validateCDA.findNodesFromDoc(cdaDocument, findConditionStr);//暂时没有验证
            //
            //			//6、设置返回结果
            //			if(boolResult)
            //			{
            //				resultMessage = cdaDocument.asXML();
            //
            //				resultMessage = resultMessage.replaceAll("type=", "xsi:type=");
            //			}
            //			else
            //			{
            //				//将存在异常的节点（包括父节点和当前节点）输出到控制台，供开发调试用
            //				for (Iterator<String> iterator = errorElementStrlist.iterator(); iterator.hasNext();)
            //				{
            //					String exceptionElementStr = (String) iterator.next();
            //
            //					LOGGER.info("--> 异常的节点（包括父节点和当前节点）:" + exceptionElementStr);
            //				}
            //
            //				resultMessage = "生成CDA文档出现异常，请检查数据是否正确!";
            //			}

            //删除 xsi:type 节点 替换为type
            String cdaStr = cdaDocument.asXML();
            cdaStr = cdaStr.replace("type=", "xsi:type=");
            cdaDocument = DocumentHelper.parseText(cdaStr);

            //LOGGER.info("--> 跳过验证");

            //开始校验CDA文档
            //LOGGER.info("-->需要校验的 CDA文档:"+cdaDocument.asXML());
            LOGGER.info("-->开始验证");

            //验证CDA文档
            //result = CDASchemaValidateTool.validateCDA(cdaDocument, "/common/resource/sdschemas/PCHIS_CDA.xsd");
            result.put("YZJG", "AA");
            result.put("YZJGSM", "共享文档格式验证成功");
            LOGGER.info("-->结束验证");

            //CDA验证
            /**
             String xsdFilePath = "/common/resource/sdschemas/PCHIS_CDA.xsd";
             String serverFilePath = FrameworkServlet.getServerFilePath();
             String filePath = serverFilePath;
             LOGGER.info("--> PCHIS_CDA.xsd 文件路径：" + filePath+"/"+xsdFilePath);
             result = (HashMap<String, Object>) validateXml(filePath+"/"+xsdFilePath,cdaDocument);
             LOGGER.info("-->验证CDA文档格式返回验证结果："+result.toString());
             **/

            result.put("cdaDocument", cdaDocument.asXML());

        } catch (Exception e) {
            //			errorMessage = "生成CDA文档出现异常，异常信息：" + e.getMessage();
            //			LOGGER.info(errorMessage);
            LOGGER.error(e, e.fillInStackTrace());
            e.printStackTrace();

        }
        return result;
    }

    /**
     * 生成一份CDA文档，由于存在重复Entry既条目明细等情况，一次只能生成一份CDA
     * 方法名称: createOneCDADocumentService
     *
     * @param xm              患者姓名
     * @param requestID       请求ID，由机构代码_证件号码_GUID值合并而成
     * @param cdaTempFileName cda模板名称，一份模块对应一类电子档案信息
     * @param basicSQL        提供查询一份CDA基本信息的sql语句
     *                        void  返回类型说明
     * @author liuwensheng@winning.com.cn<br/>
     * 创建时间：2017-1-11/下午2:56:11<br/>
     */
    @Override
    public HashMap<String, Object> createOneCDADocumentService(String xm, String requestID, String cdaTempFileName,
                                                               String basicSQL, Object[] param, String dbDataSourceID) {


        String errorMessage = null;

        //String propValue = CDATempBeanConfig.getInstance().getProperty("useDefaultValue");
        //useDefaultValue =  "true".equals(propValue) == true ? true : false;

        String resultMessage = "";

        List<HashMap<String, Object>> rowListValue = new ArrayList<HashMap<String, Object>>();

        //"CDATemp.xml"
        //CDATempBeanConfig cdaConfig = CDATempBeanConfig.getInstance();
        Document cdaDocument = DocumentHelper.createDocument();
        //设置文档编码
        cdaDocument.setXMLEncoding("utf-8");

        String cdaFileName = cdaTempFileName + "_" + xm + " _" + requestID;

        HashMap<String, Object> result = new HashMap<String, Object>();

        try {
            //获取XML文档DOM
            String cdaTempFilePath = "com/winning/ihe/cda/cdaTempFiles/" + cdaTempFileName + ".xml";

            Document configDocument = XMLTool.getXMLDocument(cdaTempFilePath);

            Element rootElementReader = configDocument.getRootElement();

            //将requestID存入返回结果中，生成CDA文档的ID节点
            String str = "'" + requestID + "'  as  REQUESTID,";
            basicSQL = "SELECT " + str + basicSQL.substring(6, basicSQL.length());

            //0、执行数据库操作
            LOGGER.info("-->查询CDA信息SQL：" + basicSQL);
//            LOGGER.info("-->查询CDA信息SQL参数：" + param[0]);

            rowListValue = ServerSQLExecutorUtils.executeQueryOtherDB(basicSQL, param, dbDataSourceID);

            //将数据结果集转换为map结构，key为模板配置中的columnFeild值
            //rowListValue = sealDBTableValue(rs);

            if (null == rowListValue || rowListValue.size() == 0) {
                LOGGER.info("生成CDA文档出现异常，异常信息：没有需要生成数据1111111111");

                return null;
            }

            //需要根据数据库查询结果，对CDA模板配置动态更新Entry节点
            updateCDATempConfig(configDocument, rowListValue);

            String rootElementName = XMLTool.getAttributeValue(rootElementReader, IHEConstans.ROOT_ELEMENT_NAME_TEMP);

            //取得模板配置中的对CDA文档节点的验证
            //String findConditionStr = rootElementReader.attributeValue(IHEConstans.VALIDATE_NODES_TEMP) == null ? "" : rootElementReader.attributeValue(IHEConstans.VALIDATE_NODES_TEMP);

            //Root根目录添加命名空间需要在创建根Element时，添加命名空间值，这样在给root element添加属性"xmlns"时才生效
            Element cdaRootElement = cdaDocument.addElement(rootElementName, IHEConstans.NAMP_SPACE_XMLNS_VALUE);

            //1、命名空间属性
            Element nameSpaceElement = rootElementReader.element(IHEConstans.NAME_SPACES_TEMP);
            createNameSpaceElement(nameSpaceElement, cdaRootElement);

            //2、请求头结构
            Element headerElement = rootElementReader.element(IHEConstans.HEADER_ELEMENTS_TEMP);
            createHeaderElement(headerElement, cdaRootElement, rowListValue);

            //3、请求体结构
            Element bodyElement = rootElementReader.element(IHEConstans.BODY_ELEMENTS_TEMP);
            createBobyElement(bodyElement, cdaRootElement, rowListValue);

            //还没有进行下一步的验证算法
            errorMessage = searchErrorNodeToMessage(cdaDocument);
            ValidateCDA validateCDA = new ValidateCDA();

            /*******************************************************************
             在此处输出验证前的文档
             /*******************************************************************/
            XMLWriter writer = new XMLWriter(new FileOutputStream("c://DemoX.xml"));
            writer.write(cdaDocument);

            //4.非空验证及更新：将存在异常error的节点删除，异常根据配置中参数的非空约束获得
            cdaDocument = validateCDA.updateCDAXMLForDocument(cdaDocument, cdaFileName);

            //			//5.对生成的CDA文档进行节点校验
            //			boolean boolResult = true; //validateCDA.findNodesFromDoc(cdaDocument, findConditionStr);//暂时没有验证
            //
            //			//6、设置返回结果
            //			if(boolResult)
            //			{
            //				resultMessage = cdaDocument.asXML();
            //
            //				resultMessage = resultMessage.replaceAll("type=", "xsi:type=");
            //			}
            //			else
            //			{
            //				//将存在异常的节点（包括父节点和当前节点）输出到控制台，供开发调试用
            //				for (Iterator<String> iterator = errorElementStrlist.iterator(); iterator.hasNext();)
            //				{
            //					String exceptionElementStr = (String) iterator.next();
            //
            //					LOGGER.info("--> 异常的节点（包括父节点和当前节点）:" + exceptionElementStr);
            //				}
            //
            //				resultMessage = "生成CDA文档出现异常，请检查数据是否正确!";
            //			}

            //删除 xsi:type 节点 替换为type
            String cdaStr = cdaDocument.asXML();
            cdaStr = cdaStr.replace("type=", "xsi:type=");
            cdaDocument = DocumentHelper.parseText(cdaStr);

            //LOGGER.info("--> 跳过验证");

            //开始校验CDA文档
            //LOGGER.info("-->需要校验的 CDA文档:"+cdaDocument.asXML());
            LOGGER.info("-->开始验证");

            //验证CDA文档
            //result = CDASchemaValidateTool.validateCDA(cdaDocument, "/common/resource/sdschemas/PCHIS_CDA.xsd");
            result.put("YZJG", "AA");
            result.put("YZJGSM", "共享文档格式验证成功");
            LOGGER.info("-->结束验证");

            //CDA验证
            /**
             String xsdFilePath = "/common/resource/sdschemas/PCHIS_CDA.xsd";
             String serverFilePath = FrameworkServlet.getServerFilePath();
             String filePath = serverFilePath;
             LOGGER.info("--> PCHIS_CDA.xsd 文件路径：" + filePath+"/"+xsdFilePath);
             result = (HashMap<String, Object>) validateXml(filePath+"/"+xsdFilePath,cdaDocument);
             LOGGER.info("-->验证CDA文档格式返回验证结果："+result.toString());
             **/

            result.put("cdaDocument", cdaDocument.asXML());

        } catch (Exception e) {
            //			errorMessage = "生成CDA文档出现异常，异常信息：" + e.getMessage();
            //			LOGGER.info(errorMessage);
            LOGGER.error(e, e.fillInStackTrace());
            e.printStackTrace();
        }

        return result;
    }


    @Override
    public HashMap<String, Object> createOneCDADocumentService(String xm, String requestID, String cdaTempFileName,
                                                               List<HashMap<String, Object>> rowListValue) {
        String errorMessage = null;

        String resultMessage = "";

        //"CDATemp.xml"
        //CDATempBeanConfig cdaConfig = CDATempBeanConfig.getInstance();
        Document cdaDocument = DocumentHelper.createDocument();
        //设置文档编码
        cdaDocument.setXMLEncoding("utf-8");

        String cdaFileName = cdaTempFileName + "_" + xm + " _" + requestID;

        HashMap<String, Object> result = new HashMap<String, Object>();

        try {
            //获取XML文档DOM
            String cdaTempFilePath = "com/winning/ihe/cda/cdaTempFiles/" + cdaTempFileName + ".xml";

            Document configDocument = XMLTool.getXMLDocument(cdaTempFilePath);

            Element rootElementReader = configDocument.getRootElement();

            //将requestID存入返回结果中，生成CDA文档的ID节点


            //0、执行数据库操作

            //将数据结果集转换为map结构，key为模板配置中的columnFeild值
            //rowListValue = sealDBTableValue(rs);

            if (null == rowListValue || rowListValue.size() == 0) {
                LOGGER.info("生成CDA文档出现异常，异常信息：没有需要生成数据1111111111111111111111");

                return null;
            }

            //需要根据数据库查询结果，对CDA模板配置动态更新Entry节点
            updateCDATempConfig(configDocument, rowListValue);

            String rootElementName = XMLTool.getAttributeValue(rootElementReader, IHEConstans.ROOT_ELEMENT_NAME_TEMP);

            //取得模板配置中的对CDA文档节点的验证
            //String findConditionStr = rootElementReader.attributeValue(IHEConstans.VALIDATE_NODES_TEMP) == null ? "" : rootElementReader.attributeValue(IHEConstans.VALIDATE_NODES_TEMP);

            //Root根目录添加命名空间需要在创建根Element时，添加命名空间值，这样在给root element添加属性"xmlns"时才生效
            Element cdaRootElement = cdaDocument.addElement(rootElementName, IHEConstans.NAMP_SPACE_XMLNS_VALUE);

            //1、命名空间属性
            Element nameSpaceElement = rootElementReader.element(IHEConstans.NAME_SPACES_TEMP);
            createNameSpaceElement(nameSpaceElement, cdaRootElement);

            //2、请求头结构
            Element headerElement = rootElementReader.element(IHEConstans.HEADER_ELEMENTS_TEMP);
            createHeaderElement(headerElement, cdaRootElement, rowListValue);

            //3、请求体结构
            Element bodyElement = rootElementReader.element(IHEConstans.BODY_ELEMENTS_TEMP);
            createBobyElement(bodyElement, cdaRootElement, rowListValue);

            //还没有进行下一步的验证算法
            errorMessage = searchErrorNodeToMessage(cdaDocument);
            ValidateCDA validateCDA = new ValidateCDA();

            /*******************************************************************
             在此处输出验证前的文档
             /*******************************************************************/
            XMLWriter writer = new XMLWriter(new FileOutputStream("c://DemoX.xml"));
            writer.write(cdaDocument);

            //4.非空验证及更新：将存在异常error的节点删除，异常根据配置中参数的非空约束获得
            cdaDocument = validateCDA.updateCDAXMLForDocument(cdaDocument, cdaFileName);

            //			//5.对生成的CDA文档进行节点校验
            //			boolean boolResult = true; //validateCDA.findNodesFromDoc(cdaDocument, findConditionStr);//暂时没有验证
            //
            //			//6、设置返回结果
            //			if(boolResult)
            //			{
            //				resultMessage = cdaDocument.asXML();
            //
            //				resultMessage = resultMessage.replaceAll("type=", "xsi:type=");
            //			}
            //			else
            //			{
            //				//将存在异常的节点（包括父节点和当前节点）输出到控制台，供开发调试用
            //				for (Iterator<String> iterator = errorElementStrlist.iterator(); iterator.hasNext();)
            //				{
            //					String exceptionElementStr = (String) iterator.next();
            //
            //					LOGGER.info("--> 异常的节点（包括父节点和当前节点）:" + exceptionElementStr);
            //				}
            //
            //				resultMessage = "生成CDA文档出现异常，请检查数据是否正确!";
            //			}

            //删除 xsi:type 节点 替换为type
            String cdaStr = cdaDocument.asXML();
            cdaStr = cdaStr.replace("type=", "xsi:type=");
            cdaDocument = DocumentHelper.parseText(cdaStr);

            //LOGGER.info("--> 跳过验证");

            //开始校验CDA文档
            //LOGGER.info("-->需要校验的 CDA文档:"+cdaDocument.asXML());
            LOGGER.info("-->开始验证");

            //验证CDA文档
            //result = CDASchemaValidateTool.validateCDA(cdaDocument, "/common/resource/sdschemas/PCHIS_CDA.xsd");
            result.put("YZJG", "AA");
            result.put("YZJGSM", "共享文档格式验证成功");
            LOGGER.info("-->结束验证");

            //CDA验证
            /**
             String xsdFilePath = "/common/resource/sdschemas/PCHIS_CDA.xsd";
             String serverFilePath = FrameworkServlet.getServerFilePath();
             String filePath = serverFilePath;
             LOGGER.info("--> PCHIS_CDA.xsd 文件路径：" + filePath+"/"+xsdFilePath);
             result = (HashMap<String, Object>) validateXml(filePath+"/"+xsdFilePath,cdaDocument);
             LOGGER.info("-->验证CDA文档格式返回验证结果："+result.toString());
             **/

            result.put("cdaDocument", cdaDocument.asXML());

        } catch (Exception e) {
            //			errorMessage = "生成CDA文档出现异常，异常信息：" + e.getMessage();
            //			LOGGER.info(errorMessage);
            LOGGER.error(e, e.fillInStackTrace());
            e.printStackTrace();
        }

        return result;
    }

    public Map<String, Object> validateXml(String xsdPath, Document xmlDoc) throws SAXException, IOException {
        Map<String, Object> result = new HashMap<String, Object>();
        SchemaErrorHandler errorHandler = new SchemaErrorHandler();
        // 建立schema工厂
        SchemaFactory schemaFactory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
        // 建立验证文档文件对象，利用此文件对象所封装的文件进行schema验证
        File schemaFile = new File(xsdPath);
        // 利用schema工厂，接收验证文档文件对象生成Schema对象
        Schema schema = schemaFactory.newSchema(schemaFile);
        // 通过Schema产生针对于此Schema的验证器，利用schenaFile进行验证
        Validator validator = schema.newValidator();
        // 得到验证的数据源
        Source source = new StreamSource(new ByteArrayInputStream(xmlDoc.asXML().getBytes("utf-8")));
        // 开始验证，成功输出success!!!，失败输出fail
        validator.validate(source);
        validator.setErrorHandler(errorHandler);
        //验证有没有错误
        SchemaSummary summary = new SchemaSummary();
        summary.fromSchemaResultDocument(errorHandler.getReport());
        LOGGER.info("-->CDA文档错误详情：" + errorHandler.getReport().asXML());
        if (summary.getErrorCount() > 0) {
            result.put("YZJG", "AE");
            result.put("YZJGSM", "错误详情：" + errorHandler.getReport().asXML());
            LOGGER.info("-->共享文档格式验证失败!错误详情：" + errorHandler.getReport().asXML());

        } else {
            result.put("YZJG", "AA");
            result.put("YZJGSM", "共享文档格式验证成功");
            LOGGER.info("-->共享文档格式验证成功!");
        }
        return result;
    }

    /**
     * 从CDA文档中查找还没有经过验证的初级error校验位置
     *
     * @param document
     * @return
     */
    @SuppressWarnings("unchecked")
    private String searchErrorNodeToMessage(Document document) {
        String resultMessage = "";

        String errorElementXPath = "//*[@result='error']";

        if (null != document) {
            List<Element> errorElement = document.selectNodes(errorElementXPath);

            for (Iterator<Element> iterator = errorElement.iterator(); iterator.hasNext(); ) {
                Element element = (Element) iterator.next();

                //返回存在异常的节点字符串
                String xmlPath = element.getPath().replace("*[name()='", "").replace("']", "");
                String errorStr = xmlPath;
                resultMessage += errorStr + ";\n";
            }
        }

        return resultMessage;

    }

    /**
     * 根据CDA模板配置的可能出现重复节点的更新流程
     * 需要设置XPATH获取搜索路径，找到需要重复的节点，并按照重复节点的数量，更新父节点，
     * XPATH需要设置特定条件：待重复的节点需要设置UUID，在配置文件中使用，跟CDA生成文档没有关系
     *
     * @param document
     */
    @SuppressWarnings({"unchecked", "deprecation"})
    private void updateCDATempConfig(Document document, List<HashMap<String, Object>> rowListValue) {
        Element rootElement = document.getRootElement();

        List<Element> repeatPramasElementList = rootElement.elements(IHEConstans.REPEAT_PARAMS_TEMP);

        if (null != repeatPramasElementList && repeatPramasElementList.size() > 0) {
            Element repeatPramasElement = repeatPramasElementList.get(0);

            List<Element> repeatPramaElementList = repeatPramasElement.elements();

            //遍历查询出模板配置文件中的XPATH
            for (Iterator<Element> iterator = repeatPramaElementList.iterator(); iterator.hasNext(); ) {
                Element element = (Element) iterator.next();
                //获取xpath路径
                String xPathStr = element.attributeValue(IHEConstans.XPATH_TEMP);

                //查找可能出现重复的节点列表
                List<Element> repeatElementList = document.selectNodes(xPathStr);

                Iterator<Element> iter = repeatElementList.iterator();

                //遍历重复的节点属性
                while (iter.hasNext()) {
                    Element repeatElement = (Element) iter.next();

                    Element parentElement = repeatElement.getParent();

                    //给第一个模板节点增加数据库查询结果集下标
                    repeatElement.setAttributeValue(IHEConstans.ROW_INDEX_TEMP, "0");
                    setAttrubteRecursion(repeatElement, IHEConstans.ROW_INDEX_TEMP, "0");

                    //出现重复的次数,需要根据目前数据库表结果集行数
                    int repeatElementCount = rowListValue.size();

                    //动态给新增的重复节点增加数据库查询结果集下标
                    for (int index = 0; index < repeatElementCount; index++) {
                        Element newElement = (Element) repeatElement.clone();

                        String rowIndexStr = String.valueOf(index + 1);
                        newElement.setAttributeValue(IHEConstans.ROW_INDEX_TEMP, rowIndexStr);

                        setAttrubteRecursion(newElement, IHEConstans.ROW_INDEX_TEMP, rowIndexStr);

                        parentElement.add(newElement);
                    }
                }
            }
        }
    }

    /**
     * 创建CDA文档根节点的命名空间
     *
     * @param nameSpaceElement
     * @param cdaRootElement
     */
    @SuppressWarnings({"unchecked", "deprecation"})
    private void createNameSpaceElement(Element nameSpaceElement, Element cdaRootElement) {
        if (null != nameSpaceElement) {
            List<Element> nameSpaceElementList = nameSpaceElement.elements();

            for (Iterator<Element> iterator = nameSpaceElementList.iterator(); iterator.hasNext(); ) {
                Element element = (Element) iterator.next();

                String attributeName = element.attributeValue(IHEConstans.ATTRIBUT_NAME_TEMP);
                String attributeValue = element.attributeValue(IHEConstans.ATTRIBUT_VALUE_TEMP);

                cdaRootElement.addNamespace(attributeName, attributeValue);
                //cdaRootElement.setAttributeValue(attributeName, attributeValue);
            }
        }

    }

    /**
     * 创建CDA文档头结构
     *
     * @param headerElement
     * @param cdaRootElement
     */
    private void createHeaderElement(Element headerElement, Element cdaRootElement,
                                     List<HashMap<String, Object>> rowListValue) {
        if (null != headerElement) {
            //开始递归生成cda节点
            createElementRecursion(headerElement, cdaRootElement, rowListValue);
        }

    }

    /**
     * 创建CDA文档体, 追随完成CDA请求头后的文档结构
     *
     * @param bodyElement
     * @param cdaRootElement
     */
    private void createBobyElement(Element bodyElement, Element cdaRootElement,
                                   List<HashMap<String, Object>> rowListValue) {
        if (null != bodyElement) {
            createElementRecursion(bodyElement, cdaRootElement, rowListValue);
        }

    }

    /**
     * 统一创建子节点和属性的接口
     * 根据配置模板节点Element递归给CDA文档节点动态添加子节点或者子节点属性
     *
     * @param element    模块文档中的节点
     * @param cdaElement 待生成的CDA文档节点
     */
    @SuppressWarnings({"unchecked"})
    private void createElementRecursion(Element element, Element cdaElement,
                                        List<HashMap<String, Object>> rowListValue) {
        if (null != element) {

            List<Element> elementChildList = element.elements();

            for (Iterator<Element> iterator = elementChildList.iterator(); iterator.hasNext(); ) {
                Element elementChild = (Element) iterator.next();

                String elementQNameStr = elementChild.getName();

                //提取配置文档中的节点、属性的约束条件
                String restraint = "restraint";
                String restraintValue = elementChild.attributeValue("restraint");

                //优先检查Element中是否配置了columnFeild字段，如果配置，则优先从数据库结果集中获取属性值, 反之取配置属性值
                //需要对节点进行验证是否需要文本值(这里是表字段)。<test/>、<test>lllllll</test>
                String columnFeild = elementChild.attributeValue(IHEConstans.COLUMN_NAME_TEMP);

                //数据结构集中的行数下标
                int rowIndex = Integer.valueOf(elementChild.attributeValue(IHEConstans.ROW_INDEX_TEMP) == null ? "0"
                        : elementChild.attributeValue(IHEConstans.ROW_INDEX_TEMP));

                //如果是Element节点，则创建子节点
                if (IHEConstans.ELEMENT_TEMP.equals(elementQNameStr)) {
                    String childElementNameStr = elementChild.attributeValue(IHEConstans.ELEMENT_NAME_TEMP);
                    //需要对节点进行验证是否需要文本值(这里是默认值)。<test/>、<test>lllllll</test>
                    String childElementTextStr = elementChild.attributeValue(IHEConstans.ELEMENT_VALUE_TEMP);

                    Element cadElemntChild = cdaElement.addElement(childElementNameStr);

                    String textValue = "";

                    //1、优先从数据库中取值
                    if (null != columnFeild && !"".equals(columnFeild)) {
                        textValue = getColumnValueByFeild(columnFeild, rowListValue, rowIndex);

                        //如果数据库中查询不到值，则采用默认设置的值
                        if (useDefaultValue && (null == textValue || "".equals(textValue))) {
                            if (null != childElementTextStr && !"".equals(childElementTextStr)) {
                                textValue = childElementTextStr;
                            }
                        }
                    }
                    //给Element设置字符文本值, text不能为null
                    else if (null != childElementTextStr && !"".equals(childElementTextStr)) {
                        textValue = childElementTextStr;
                    }

                    //2、非空验证
                    if (null != textValue && !"".equals(textValue)) {
                        //Element的值为文本值
                        cadElemntChild.setText(textValue);
                    } else {
                        //如果约束条件规定节点文本值为必填，则当value为空时，标记该节点错误
                        if ("1..1".equals(restraintValue) || "1..*".equals(restraintValue)) {
                            //这里需要验证，该节点是否需要采用配置默认值、表数据来作为节点文本值的填充，如果需要，而且必填，则出现异常
                            if (isExitAttribute(elementChild, IHEConstans.ELEMENT_VALUE_TEMP)
                                    || isExitAttribute(elementChild, IHEConstans.COLUMN_NAME_TEMP)) {
                                cadElemntChild.addAttribute("result", "error");
                            }
                        }
                        //如果约束条件规定节点文本值为必填，则当value为空时，该节点不做处理
                        else {

                        }
                    }

                    //将节点约束条件生成到CDA临时文档中，作为验证CDA文档的条件， 如果条件为1..1\1..*，value值为空，则节点异常
                    cadElemntChild.addAttribute(restraint, restraintValue);

                    //递归子Element配置
                    createElementRecursion(elementChild, cadElemntChild, rowListValue);
                }
                //如果是Attribute属性，则给Element增加属性值
                else if (IHEConstans.ATTRIBUT_TEMP.equals(elementQNameStr)) {
                    String attributeName = elementChild.attributeValue(IHEConstans.ATTRIBUT_NAME_TEMP);
                    String attributeValue = elementChild.attributeValue(IHEConstans.ATTRIBUT_VALUE_TEMP);

                    String newAttributeValue = "";

                    //1、优先从数据库中取值
                    if (null != columnFeild && !"".equals(columnFeild)) {
                        newAttributeValue = getColumnValueByFeild(columnFeild, rowListValue, rowIndex);

                        //如果数据库中查询不到值，则采用默认设置的值
                        if (useDefaultValue && (null == newAttributeValue || "".equals(newAttributeValue))) {
                            if (null != attributeValue && !"".equals(attributeValue)) {
                                newAttributeValue = attributeValue;
                            }
                        }
                    } else if (null != attributeValue && !"".equals(attributeValue)) {
                        newAttributeValue = attributeValue;
                    }

                    //2、对属性值做非空验证，利用约束性(1..1\1..*)R为必填，(0..1\0..*)O为非必填
                    if (null != newAttributeValue && !"".equals(newAttributeValue)) {
                        //cdaElement.setAttributeValue(attributeName, newAttributeValue);
                        cdaElement.addAttribute(attributeName, newAttributeValue);
                    } else {
                        //如果约束条件规定属性为必填，则当value为空时，标记该节点错误
                        if ("1..1".equals(restraintValue) || "1..*".equals(restraintValue)) {
                            cdaElement.addAttribute("result", "error");

                            //cdaElement.setAttributeValue(attributeName, newAttributeValue);
                            cdaElement.addAttribute(attributeName, newAttributeValue);
                        }
                        //如果约束条件规定属性为非必填，则当value为空时，该节点属性可以不生成
                        else {

                        }
                    }

                    //需要做非空验证，在模板配置参数中提供字段判断非空,如果为必填项，而从数据库中取到的值为null或者""，则给该节点设置标记错误属性result='error'
                    //setResultToAttrbute(element, cdaElement, attributeValue);
                }
            }

        }

    }

    /**
     * 解析数据库返回的结果集，根据配置文件封装数据结构
     *
     * @param rs 数据结果集
     * @return
     */
    private List<HashMap<String, Object>> sealDBTableValue(ResultSet rs) {
        //所有行数据列表:存放经过列表转换、字段值截取、字段值转义操作后的最新结果集
        List<HashMap<String, Object>> rowListValue = new ArrayList<HashMap<String, Object>>();

        try {
            //获得列集
            ResultSetMetaData rsm = rs.getMetaData();

            //获得列的个数
            int col = rsm.getColumnCount();

            //取结果集中的数据, 按照列字段和Value进行封装
            while (rs.next()) {
                HashMap<String, Object> columnObjectMap = new HashMap<String, Object>();

                //遍历每一行数据中的每一个列，对列数据进行配置化转换:1.列字段名称转换； 2.列值长度截取；3.列值转义
                for (int j = 0; j < col; j++) {
                    String columnNameStr = rsm.getColumnName(j + 1);
                    Object valueObject = rs.getObject(columnNameStr);

                    //统一将表字段值转换成String类型处理
                    String columnValueStr = valueObject == null ? "" : valueObject.toString();

                    //列名字转换大写, 为了和配置文件一直
                    String upperColumnNameStr = columnNameStr.toUpperCase();

                    columnObjectMap.put(upperColumnNameStr, columnValueStr);
                }

                rowListValue.add(columnObjectMap);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (rs != null) {
                    //需要关闭数据库结果集
                    rs.close();
                    rs = null;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return rowListValue;
    }

    /**
     * 目前只能根据数据集的行数，来设置CDA中的某些节点的重复，如:条目
     *
     * @param columnFeild
     * @param rowListValue
     * @return
     */
    private String getColumnValueByFeild(String columnFeild, List<HashMap<String, Object>> rowListValue, int rowIndex) {
        //根据行数来取动态值
        HashMap<String, Object> hashMap = (HashMap<String, Object>) rowListValue.get(rowIndex);

        String resultStr = hashMap.get(columnFeild.toUpperCase()) == null ? ""
                : hashMap.get(columnFeild.toUpperCase()).toString();

        return resultStr;
    }

    /**
     * 利用递归算法实现对子节点的属性设置
     *
     * @param element
     * @param attributeName
     * @param attributeValue
     */
    @SuppressWarnings({"unchecked", "deprecation"})
    private void setAttrubteRecursion(Element element, String attributeName, String attributeValue) {
        List<Element> childElementList = element.elements();

        //循环遍历子节点，如果没有子节点，则递归结束
        for (Iterator<Element> iterator = childElementList.iterator(); iterator.hasNext(); ) {
            Element childElement = (Element) iterator.next();

            childElement.setAttributeValue(attributeName, attributeValue);

            //需要递归设置子节点的属性值
            setAttrubteRecursion(childElement, attributeName, attributeValue);
        }
    }

    /**
     * 验证指定的节点属性是否存在，根据属性的名称判断
     *
     * @param elementChild
     * @param nameValue
     * @return
     */
    @SuppressWarnings("unchecked")
    private boolean isExitAttribute(Element elementChild, String nameValue) {
        boolean isExit = false;

        if (null != elementChild) {
            List<Attribute> list = elementChild.attributes();

            for (Iterator<Attribute> iterator = list.iterator(); iterator.hasNext(); ) {
                Attribute attribute = (Attribute) iterator.next();

                String attributeName = attribute.getName();

                if (nameValue.equals(attributeName)) {
                    isExit = true;
                    break;
                }
            }
        }

        return isExit;
    }

}
